package com.cqfae.deploycentral.app.services.impl;

import com.cqfae.deploycentral.api.utils.IdGenerator;
import com.cqfae.deploycentral.app.dao.entity.*;
import com.cqfae.deploycentral.app.dao.mapper.*;
import com.cqfae.deploycentral.app.services.ExpectPublishEnqueueService;
import com.cqfae.deploycentral.app.services.ReportInfoService;
import com.cqfae.deploycentral.app.services.WindowPlansService;
import com.cqfae.deploycentral.app.utils.ConvertUtil;
import com.cqfae.deploycentral.app.utils.NullUtil;
import com.cqfae.deploycentral.app.web.vo.WindowPlansFilesVo;
import com.cqfae.deploycentral.app.web.vo.WindowPlansVo;
import org.apache.ibatis.exceptions.TooManyResultsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import static com.cqfae.deploycentral.app.base.BaseConstantCode.*;

@Service
@Transactional
public class ExpectPublishEnqueueServiceImpl implements ExpectPublishEnqueueService {

    private static Logger logger = LoggerFactory.getLogger(ExpectPublishEnqueueServiceImpl.class);

    @Autowired
    private IdGenerator idGenerator;

    @Autowired
    private ReportInfoService reportInfoService;

    @Autowired
    private WindowPlansService windowPlansService;

    @Autowired
    private WindowPlansFilesMapper windowPlansFilesMapper;

    @Autowired
    private ApproveDocumentMapper approveDocumentMapper;

    @Autowired
    private ApproveAttachmentMapper approveAttachmentMapper;

    @Autowired
    private ExpectPublishEnqueueMapper expectPublishEnqueueMapper;

    @Autowired
    private WindowPlansMapper windowPlansMapper;

    @Autowired
    private ReportTestLinkMapper reportTestLinkMapper;

    @Autowired
    private ReportInfoMapper reportInfoMapper;

    @Override
    public int save(ExpectPublishEnqueue expectPublishEnqueue){
        //Step 1 校验：以reportCode进行查重检验；入参的非空校验
        String reportCode = expectPublishEnqueue.getReportCode();
        if(NullUtil.isNotEmpty(enqueueInfoByReportCode(reportCode))){
            logger.info( "=========Fail :insert ReportCode is Repeat ========",reportCode);
            return INSERT_EXPECTPUBLISHENQUEUE_FAIL_CODE_REPEAT;
        }
        if(NullUtil.isEmpty(expectPublishEnqueue.getTestStatus()) && NullUtil.isEmpty( reportCode )){
            logger.info( "=========Fail :insert ExpectPublishEnqueue lost param ========",reportCode);
            return INSERT_EXPECTPUBLISHENQUEUE_FAIL_CODE_LOSTPARAM;
        }
        //Step 2 组合待发布队列信息表的参数
        expectPublishEnqueue.setId(idGenerator.nextId());
        expectPublishEnqueue.setApproveStatus(APPROVE_STATUS_UNTREATED_CODE);
        expectPublishEnqueue.setApprovePlanNum(9999);
        expectPublishEnqueue.setApproveCompleteNum(0);
        expectPublishEnqueue.setReserved1(Integer.toString(SCHEDULED_EXEC_NOTHING));
        expectPublishEnqueue.setCreateBy("123");
        expectPublishEnqueue.setCreateTime(new Date());
        expectPublishEnqueueMapper.insert(expectPublishEnqueue);
        return MODIFY_SUCCESS_CODE;
    }

    @Override
    public ExpectPublishEnqueue enqueueInfoByReportCode(String reportCode){
        //待发布对列表的reportCode有唯一约束
        ExpectPublishEnqueue expectPublishEnqueue = new ExpectPublishEnqueue();
        expectPublishEnqueue.setReportCode(reportCode);
        try{
            return expectPublishEnqueueMapper.selectOne(expectPublishEnqueue);
        }catch (TooManyResultsException e){
            logger.info( "============= ExpectPublishEnqueue have Repeat reportCode ===================",e);
        }
        return expectPublishEnqueue;
    }

    @Override
    public int updateExpectPublish(){
        //Step 1 排除不需要更新的队列信息
        List<ExpectPublishEnqueue> expectPublishEnqueueList = checkExpectList(false);
        if(expectPublishEnqueueList.isEmpty()){
            return MODIFY_NOUPDATE_CODE;
        }
        //Step 2 循环遍历需要更新的队列，修改评审完成数和评审状态，修改信息（Tips:首先判断测试报告号是否已与评审关联）
        int updateCount = expectPublishEnqueueList.size();
        int updateCountReal = 0;
        for(ExpectPublishEnqueue enqueue:expectPublishEnqueueList){
            writeAppIdToApprove(enqueue.getReportCode());
            int approvePlanNum = testLinkByReportCode(enqueue.getReportCode()).size();
            int approveCompleteNum = getApproveCompleteNum(enqueue.getReportCode());
            if(approvePlanNum == approveCompleteNum){
                enqueue.setApproveStatus(APPROVE_STATUS_SUCCESS_CODE);
            }else{
                enqueue.setApproveStatus(APPROVE_STATUS_FAIL_CODE);
            }
            enqueue.setApproveCompleteNum(approveCompleteNum);
            enqueue.setApprovePlanNum(approvePlanNum);
            enqueue.setId(enqueue.getId());
            enqueue.setUpdateBy( "123");
            enqueue.setUpdateTime( new Date() );
            updateCountReal += expectPublishEnqueueMapper.updateByPrimaryKeySelective(enqueue);
        }
        //Step 4 是否需改完整将作为计划是否成功执行的依据
        if(updateCount == updateCountReal){
            return MODIFY_SUCCESS_CODE;
        }else{
            return MODIFY_FAIL_CODE;
        }
    }
    //Server to:updateExpectPublish()
    public int getApproveCompleteNum(String reportCode){
        //Step Pre 测试报告如果修改了对应的jira版本，若只用测试报告号查询就无法对应修改队列信息实际的完成数了
        List<ReportTestLink> reportTestLinks = testLinkByReportCode(reportCode);
        int approveCompleteNum = 0;
        for(ReportTestLink reportTestLink:reportTestLinks){
            //Step 1 根据jira版本查询对应的评审信息
            Example example = new Example(ApproveDocument.class);
            Example.Criteria ca = example.createCriteria();
            ca.andEqualTo("jiraVersionId",reportTestLink.getVersionId());
            ca.andEqualTo("approveStatus",APPROVE_STATUS_SUCCESS_CODE);
            List<ApproveDocument> approveDocuments = approveDocumentMapper.selectByExample(example);
            if(!approveDocuments.isEmpty()){
                approveCompleteNum +=1;
            }
        }
        return approveCompleteNum;
    }
    //Server to:updateExpectPublish()
    public void writeAppIdToApprove(String reportCode){

        //Step 2 查找评审信息的名称
        ReportInfo reportInfo = new ReportInfo();
        reportInfo.setReportCode(reportCode);
        reportInfo = reportInfoMapper.selectOne(reportInfo);
        String reportName = "unkown";
        if(NullUtil.isNotEmpty(reportInfo)){
            reportName = reportInfo.getTitle();
        }
        //Step 3 评审信息若为空则需要做测试报告与评审信息的关联
        List<ReportTestLink> reportTestLinks = testLinkByReportCode(reportCode);
        for(ReportTestLink testLink:reportTestLinks){
            ApproveDocument approveInfo = new ApproveDocument();
            approveInfo.setJiraVersionId(testLink.getVersionId());
            approveInfo.setApproveStatus(APPROVE_STATUS_SUCCESS_CODE);
            approveInfo = approveDocumentMapper.selectOne(approveInfo);
            if(NullUtil.isNotEmpty(approveInfo)){
                approveInfo.setAppId(Long.parseLong(reportCode));
                approveInfo.setAppName(reportName);
                approveDocumentMapper.updateByPrimaryKeySelective(approveInfo);
            }
        }
    }
    //Server to:updateExpectPublish()
    public List<ReportTestLink> testLinkByReportCode(String reportCode){
        ReportTestLink reportTestLink = new ReportTestLink();
        reportTestLink.setReportCode(reportCode);
        return reportTestLinkMapper.select(reportTestLink);
    }


    @Override
    public int autoInsertWindowPlans(){
        //Step 1 提取待发布队列中满足条件的队列信息,逻辑上保证窗口计划表的测试报告唯一性
        List<ExpectPublishEnqueue> expectPublishEnqueueList = checkExpectList(true);
        int autoInsertCount = expectPublishEnqueueList.size();
        int autoInsertCountReal = 0;
        //Step 2 每一个保存成功累加值最后等于待发布队列长度值即批处理新增成功
        for(ExpectPublishEnqueue enqueue:expectPublishEnqueueList){
            WindowPlans windowPlans = new WindowPlans();
            windowPlans.setReportCode(enqueue.getReportCode());
            List<WindowPlans> windowPlansList = windowPlansMapper.select(windowPlans);
            if(windowPlansList.isEmpty()){
                WindowPlansVo vo = packageWPlanVo(enqueue);
                autoInsertCountReal +=windowPlansService.save( vo ,true);
            }
        }
        //Step 3 是否需改完整将作为计划是否成功执行的依据
        if(autoInsertCount == autoInsertCountReal){
            return MODIFY_SUCCESS_CODE;
        }else{
            return MODIFY_FAIL_CODE;
        }
    }
    //Server to:autoInsertWindowPlans()
    public WindowPlansVo packageWPlanVo(ExpectPublishEnqueue enqueue){
        WindowPlansVo vo = new WindowPlansVo();
        List<Long> approveIds = new CopyOnWriteArrayList<>();
        //Step 1 窗口时间以评审文件(时间较为靠后)的上线时间为准,处理为格式"yyyyMMdd"的字符串
        String onlineTime = "20170101";
        ApproveDocument approveDocument = new ApproveDocument();
        approveDocument.setAppId(Long.parseLong(enqueue.getReportCode()));
        List<ApproveDocument> approveDocuments = approveDocumentMapper.select(approveDocument);
        for(ApproveDocument approveInfo:approveDocuments){
            String onlineTimeTemp = ConvertUtil.convertDSTS(approveInfo.getOnlineTime());
            if(Integer.parseInt(onlineTime)<Integer.parseInt(onlineTimeTemp)){
                onlineTime = onlineTimeTemp;
            }
            approveIds.add(approveInfo.getId());
        }
        approveIds.add(approveDocument.getId());
        int windowDate = Integer.parseInt(onlineTime);
        //Step 2 窗口附件信息使用评审文件id和文件类型documentType进行筛选
        vo = packageWPlanAttachMent(vo,approveIds);
        //Step 3 窗口JIRA信息使用reportCode在t_report_test_link中进行筛选
        String jiraCode = appendJiraInfo(enqueue.getReportCode());
        //Step 4 整合其他数据
        vo.setDeployStatus( DEPLOY_STATUS_NOBUILD );
        vo.setEnvCheck(ENV_CHECK_PASS);
        vo.setSqlCheck(SQL_CHECK_PASS);
        vo.setWindowDate(windowDate);
        vo.setJiraCode(jiraCode);
        vo.setReportCode( enqueue.getReportCode() );
        vo.setCreateBy( "123" );
        vo.setCreateTime( new Date() );
        return vo;
    }

    /**
     * 根据测试报告号对应的拼接JIRA信息
     * @param reportCode
     * @return
     */
    @Override
    public String appendJiraInfo(String reportCode){
        StringBuilder jira = new StringBuilder();
        List<ReportTestLink> reportTestLink = reportInfoService.getReportTestLink(reportCode);
        for(ReportTestLink testLink:reportTestLink){
            jira = jira.append(testLink.getVersionName()+",");
        }
        return jira.substring(0,jira.length()-1);
    }

    /**
     * 组装窗口计划附件的方法
     * @description 延续了手工插入窗口计划的逻辑。在组装的时候，就把附件数据写入窗口计划附件表(t_window_plans_files)中，
     * 返回窗口参数只有一个附件的ID,最后执行新增的时候，只是修改了原来附件的ID进行关联
     * @param vo
     * @param approveIds
     * @return WindowPlansVo
     */
    public WindowPlansVo packageWPlanAttachMent(WindowPlansVo vo,List<Long> approveIds){
        Example example = new Example(ApproveAttachment.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("approveId", approveIds);
        List<ApproveAttachment> attachmentList = approveAttachmentMapper.selectByExample(example);
        List<WindowPlansFilesVo> windowPlansFilesVoList = new ArrayList<>(  );
        for(ApproveAttachment approveAttachment:attachmentList){
            if("deployNote,onlineNote,approveDecument".contains(approveAttachment.getAttachmentType())){
                long fileId = idGenerator.nextId();
                WindowPlansFiles windowPlansFiles = new WindowPlansFiles();
                windowPlansFiles.setId(fileId);
                windowPlansFiles.setFileUrl(approveAttachment.getAttachmentPath());
                windowPlansFiles.setFileName(approveAttachment.getAttachmentName());
                windowPlansFiles.setFileType(approveAttachment.getAttachmentSuffix());
                windowPlansFiles.setCreateBy(approveAttachment.getCreateBy());
                windowPlansFiles.setCreateTime(approveAttachment.getCreateTime());
                windowPlansFilesMapper.insertSelective(windowPlansFiles);
                WindowPlansFilesVo windowPlansFilesVo = new WindowPlansFilesVo();
                windowPlansFilesVo.setFileId( fileId );
                windowPlansFilesVoList.add( windowPlansFilesVo );
            }
        }
        vo.setFileList( windowPlansFilesVoList );
        return vo;
    }



    /**
     * 查询待发布对列表中最终/非最终状态的信息
     * @param finalStatus
     * @return List<ExpectPublishEnqueue>
     */
    public List<ExpectPublishEnqueue> checkExpectList(boolean finalStatus){
        //Step 1 查询出测试状态为待发布，评审状态为同意的队列信息
        List<ExpectPublishEnqueue> expectEnqueues = expectPublishEnqueueMapper.selectAll();
        //Step 2 在第一步的基础上加上条件计划数等于完成数的队列信息
        List<ExpectPublishEnqueue> finalEnqueueList = new CopyOnWriteArrayList<>();
        List<ExpectPublishEnqueue> unfinishedEnqueueList = new CopyOnWriteArrayList<>();
        for(ExpectPublishEnqueue enqueueInfo:expectEnqueues){
            if(Integer.toString(REPORT_STATUS_WPUBLISH).equals(enqueueInfo.getTestStatus())
                    && APPROVE_STATUS_SUCCESS_CODE == enqueueInfo.getApproveStatus()){
                finalEnqueueList.add(enqueueInfo);
            }else{
                unfinishedEnqueueList.add(enqueueInfo);
            }
        }
        //Step 3 根据传入的布尔值确定返回的是最终状态队列信息/非最终状态队列信息
        if(finalStatus){
            return finalEnqueueList;
        }else {
            return unfinishedEnqueueList;
        }
    }



}
